package cn.utils;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import cn.configure.SettingConfigure;
import cn.setting.*;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
/**
 * 这是一个生成二维码的工具
 *
 * @author xbsoft2
 */
public final class QRUtils {
  private static QRCodeSetting QR_CODE_SETTING;
  private static TextSetting TEXT_SETTING;
  private static CanvasSetting CANVAS_SETTING;
  private static SaveSetting SAVE_SETTING;
  private static OtherSetting OTHER_SETTING;
  /**
   * 配置生成二维码的各个属性参数
   */
  private static void configure() throws IOException, ClassNotFoundException {
    SettingConfigure settingConfigure = SettingConfigure.getSettingConfigure();
    QRUtils.QR_CODE_SETTING = settingConfigure.getQrCodeSetting();
    QRUtils.TEXT_SETTING = settingConfigure.getTextSetting();
    QRUtils.CANVAS_SETTING = settingConfigure.getCanvasSetting();
    QRUtils.SAVE_SETTING = settingConfigure.getSaveSetting();
    QRUtils.OTHER_SETTING = settingConfigure.getOtherSetting();
  }
  /**
   * 生成二维码
   *
   * @throws WriterException 异常
   * @throws IOException     异常
   */
  public static void generateQR() throws WriterException, IOException, ClassNotFoundException {
    configure();
    BufferedImage image;
    if (TEXT_SETTING.getIsShow()) {
      image = generateQRImageWithText();
    }
    else {
      image = generateQRImage();
    }
    // 保存图片
    saveImage(image);
  }
  /**
   * 生成二维码 BufferedImage 带有文字的
   *
   * @return BufferedImage 带有文字的二维码
   * @throws WriterException 异常
   */
  private static BufferedImage generateQRImageWithText() throws WriterException, IOException, ClassNotFoundException {
    // 生成二维码 BufferedImage
    BufferedImage qrCode = generateQRImage();
    // 生成显示文字 String
    String text = generateShowText();
    // 生成一个画布
    BufferedImage canvas = generateCanvas();
    // 将二维码放到画布上
    putQRCodeOnCanvas(canvas, qrCode);
    // 将显示文字放到画布上
    putTextOnCanvas(canvas, text);
    return canvas;
  }
  /**
   * 生成二维码 BufferedImage
   *
   * @return BufferedImage 二维码
   * @throws WriterException 异常
   */
  private static BufferedImage generateQRImage() throws WriterException, IOException {
    // 获取 bitMatrix
    BitMatrix bitMatrix = generateBitMatrix();
    // 将bitMatrix转成BufferedImage
    BufferedImage image = putBitMatrixConvertIntoBufferedImage(bitMatrix);
    // 添加logo
    if (QR_CODE_SETTING.getEnableLogo()) {addLogo(image);}
    return image;
  }
  /**
   * 添加logo
   *
   * @param image 要添加logo的二维码
   */
  private static void addLogo(BufferedImage image) throws IOException {
    File file = new File(QR_CODE_SETTING.getLogo());
    if (!file.exists() || !file.isFile()) {
      throw new RuntimeException("logo路径错误:" + QR_CODE_SETTING.getLogo());
    }
    else {
      Image src = ImageIO.read(file);
      if (src == null) {throw new RuntimeException("logo文件错误:" + QR_CODE_SETTING.getLogo());}
      // 将logo宽高设置为二维码的1/6
      int width = image.getWidth() / 6;
      int height = image.getHeight() / 6;
      Image logo = src.getScaledInstance(width, height, 4);
      Graphics2D graph = image.createGraphics();
      int x = (image.getWidth() - width) / 2;
      int y = (image.getHeight() - height) / 2;
      graph.drawImage(logo, x, y, width, height, null);
      Shape shape = new RoundRectangle2D.Float((float) x, (float) y, (float) width, (float) width, 6.0F, 6.0F);
      graph.setStroke(new BasicStroke(3.0F));
      graph.draw(shape);
      graph.dispose();
    }
  }
  /**
   * 生成要画在画布上的文字
   *
   * @return 文字
   */
  private static String generateShowText() {
    return TEXT_SETTING.getPrefix() + TEXT_SETTING.getContents() + TEXT_SETTING.getSuffix();
  }
  /**
   * 保存图片
   *
   * @param newImage 要保存的图片
   */
  private static void saveImage(BufferedImage newImage) throws IOException {
    File file = new File(SAVE_SETTING.getDirectory());
    if (!file.exists()) {file.mkdirs();}
    String path = SAVE_SETTING.getDirectory() + "/" + SAVE_SETTING.getFileName() + "." + SAVE_SETTING.getFormatName();
    ImageIO.write(newImage, SAVE_SETTING.getFormatName(), new File(path));
  }
  /**
   * 将文字放到画布上
   *
   * @param text 二维码图片
   */
  private static void putTextOnCanvas(BufferedImage canvas, String text) {
    Graphics g = canvas.getGraphics();
    g.setColor(new Color(TEXT_SETTING.getColor()));
    g.setFont(new Font(TEXT_SETTING.getFontName(), TEXT_SETTING.getFontStyle(), TEXT_SETTING.getFontSize()));
    g.drawString(text, TEXT_SETTING.getX(), TEXT_SETTING.getY());
  }
  /**
   * 将二维码放到画布上
   *
   * @param canvas 画布
   * @param qrCode 二维码
   */
  private static void putQRCodeOnCanvas(BufferedImage canvas, BufferedImage qrCode) {
    Graphics g = canvas.getGraphics();
    // 将二维码画上
    g.drawImage(qrCode, QR_CODE_SETTING.getX(), QR_CODE_SETTING.getY(), QR_CODE_SETTING.getWidth(), QR_CODE_SETTING.getHeight(), null);
  }
  /**
   * 生成一块画布
   *
   * @return 画布
   */
  private static BufferedImage generateCanvas() {
    BufferedImage canvas = new BufferedImage(CANVAS_SETTING.getWidth(), CANVAS_SETTING.getHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics g = canvas.getGraphics();
    // 设置画笔颜色-白色
    g.setColor(new Color(CANVAS_SETTING.getColor()));
    // 填充整张图片为画笔当前颜色
    g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
    return canvas;
  }
  /**
   * 将BitMatrix转换成BufferedImage
   *
   * @param bitMatrix bitMatrix
   * @return BufferedImage
   */
  private static BufferedImage putBitMatrixConvertIntoBufferedImage(BitMatrix bitMatrix) {
    int width = bitMatrix.getWidth();
    int height = bitMatrix.getHeight();
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    int[] pixels = new int[width * height];
    int index = 0;
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        pixels[index++] = bitMatrix.get(x, y) ? QR_CODE_SETTING.getOnColor() : QR_CODE_SETTING.getOffColor();
      }
    }
    image.setRGB(0, 0, width, height, pixels, 0, width);
    return image;
  }
  /**
   * 生成 BitMatrix
   *
   * @return BitMatrix
   * @throws WriterException 异常
   */
  private static BitMatrix generateBitMatrix() throws WriterException {
    MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
    return multiFormatWriter.encode(QR_CODE_SETTING.getContents(), QR_CODE_SETTING.getBarcodeFormat(), QR_CODE_SETTING.getWidth(), QR_CODE_SETTING.getHeight(), QR_CODE_SETTING.getHints());
  }
}
